const Self = @This();

const std = @import("std");
const TerSeg = @import("terseg.zig");

pub const SegAdr: comptime_int = 4;
pub const SegNum: comptime_int = 1 << SegAdr;
pub const BitLen = TerSeg.BitLen;
pub const BitAdr = TerSeg.BitAdr;

pub const u = TerSeg.u;
pub const i = TerSeg.i;

segs: [SegNum]TerSeg,

pub fn init(segs: [SegNum]TerSeg) Self {
    return Self{
        .segs = segs,
    };
}

pub fn zero() Self {
    return Self{
        .segs = [_]TerSeg{TerSeg.zero()} ** SegNum,
    };
}

pub fn set(self: *Self, poses: []const i(BitAdr + SegAdr)) !void {
    for (poses) |pos| {
        const dex: u(SegAdr) = @intCast(@abs(pos) >> BitAdr);
        const bit: i(BitAdr) = @intCast(pos & (BitLen - 1));
        try self.segs[dex].set(bit);
    }
}

pub fn rst(self: *Self, poses: []const i(BitAdr + SegAdr)) !void {
    for (poses) |pos| {
        const dex: u(SegAdr) = @intCast(@abs(pos) >> BitAdr);
        const bit: i(BitAdr) = @intCast(pos & (BitLen - 1));
        try self.segs[dex].rst(bit);
    }
}

pub fn clr(self: *Self) void {
    for (self.segs) |*seg| {
        seg.clr();
    }
}

pub fn emptyQ(self: Self) bool {
    for (self.segs) |seg| {
        if (!seg.emptyQ()) return false;
    }
    return true;
}

pub fn equalQ(self: Self, other: Self) bool {
    for (self.segs, 0..) |seg, dex| {
        if (!seg.equalQ(other.segs[dex])) {
            return false;
        }
    }
    return true;
}

pub fn print(self: Self, postfix: ?[]const u8) void {
    for (self.segs) |seg| {
        seg.print(null);
    }
    if (postfix) |p| {
        std.debug.print("{s}", .{p});
    }
}

pub fn println(self: Self, postfix: []const u8) void {
    for (self.segs) |seg| {
        seg.print(null);
    }
    std.debug.print("{s}", .{postfix});
}

pub fn printPair(upper: Self, lower: Self, postfix: ?[]const u8) void {
    for (0..SegNum) |dex| {
        TerSeg.printPair(upper.segs[dex], lower.segs[dex], null);
    }
    if (postfix) |p| {
        std.debug.print("{s}", .{p});
    }
}

pub fn comm(a: Self, b: Self) Self {
    var result = Self.zero();
    for (0..SegNum) |dex| {
        result.segs[dex] = a.segs[dex].comm(b.segs[dex]);
    }
    return result;
}
